Passed
Push — master ( 4fbaec...4e6172 )
by EMP
01:08
created

main.js ➔ shieldMix   A

Complexity

Conditions 4

Size

Total Lines 21
Code Lines 16

Duplication

Lines 21
Ratio 100 %

Importance

Changes 0
Metric Value
eloc 16
dl 21
loc 21
rs 9.6
c 0
b 0
f 0
cc 4
1
"use strict";
2
3
sodium.ready.then(function() {
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
4
5
const ae = new AllEars(function(ok) {
1 ignored issue
show
Bug introduced by
The variable AllEars seems to be never declared. If this is a global, consider adding a /** global: AllEars */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
6
	if (ok) {
7
		document.getElementById("txt_skey").style.background = "#466";
8
		document.getElementById("txt_skey").maxLength = "64";
9
	} else {
10
		console.log("Failed to load All-Ears");
11
	}
12
});
13
14
function TabState(cur, max, btnDele, btnUpdt) {
15
	this.cur = cur;
16
	this.max = max;
17
	this.btnDele = btnDele;
18
	this.btnUpdt = btnUpdt;
19
}
20
21
const tabs = [
22
	new TabState(0, 0, false, true), // Inbox
23
	new TabState(0, 0, false, true), // Outbx
24
	new TabState(0, 2, true, false), // Write
25
	new TabState(0, 2, false, false), // Notes
26
	new TabState(0, 3, false, true) // Tools
27
];
28
29
let tab = 0;
30
const TAB_INBOX = 0;
31
const TAB_OUTBX = 1;
0 ignored issues
show
Unused Code introduced by
The constant TAB_OUTBX seems to be never used. Consider removing it.
Loading history...
32
const TAB_WRITE = 2;
33
const TAB_NOTES = 3;
34
const TAB_TOOLS = 4;
35
36
// Helper functions
37
function getCountryName(countryCode) {
38
	const opts = document.getElementById("gatekeeper_country");
39
40
	for (let i = 0; i < opts.length; i++) {
41
		if (opts[i].value === countryCode) {
42
			return opts[i].textContent;
43
		}
44
	}
45
46
	return "Unknown countrycode: " + countryCode;
47
}
48
49
function getCountryFlag(countryCode) {
50
	return sodium.to_string(new Uint8Array([
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
51
		240, 159, 135, 166 + countryCode.codePointAt(0) - 65,
52
		240, 159, 135, 166 + countryCode.codePointAt(1) - 65
53
	]));
54
}
55
56
function getMsgId(num) {
57
	let i;
58
	if (ae.GetExtMsgHeaders(num).toLowerCase().slice(0, 11) === "message-id:") {
59
		i = 0;
60
	} else {
61
		i = ae.GetExtMsgHeaders(num).toLowerCase().indexOf("\nmessage-id:");
62
		if (i < 1) return "ERR";
63
		i++;
64
	}
65
66
	const x = ae.GetExtMsgHeaders(num).slice(i + 11).trim();
67
	if (x[0] !== "<") return "ERR2";
68
	return x.slice(1, x.indexOf(">"));
69
}
70
71
function clearDisplay() {
72
	const el = document.getElementById("midright").children[2];
73
	if (el.children.length > 0) URL.revokeObjectURL(el.children[0].src);
1 ignored issue
show
Bug introduced by
The variable URL seems to be never declared. If this is a global, consider adding a /** global: URL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
74
	el.innerHTML = "";
75
}
76
77
function displayFile(num) {
78
	clearDisplay();
79
80
	document.getElementById("midright").scroll(0, 0);
81
	document.getElementById("btn_reply").disabled = true;
82
	document.getElementById("btn_mdele").disabled = true;
83
84
	document.getElementById("midright").children[0].hidden = true;
85
	document.getElementById("midright").children[1].textContent = ae.GetUplMsgTitle(num);
86
87
	switch (ae.GetUplMsgType(num)) {
88
		case "text":
89
			document.getElementById("midright").children[2].textContent = sodium.to_string(ae.GetUplMsgBody(num));
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
90
		break;
91
92
		case "image":
93
			const img = document.createElement("img");
94
			img.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
2 ignored issues
show
Bug introduced by
The variable Blob seems to be never declared. If this is a global, consider adding a /** global: Blob */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable URL seems to be never declared. If this is a global, consider adding a /** global: URL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
95
			document.getElementById("midright").children[2].appendChild(img);
96
		break;
97
	}
98
}
99
100
function displayMsg(isInt, num) {
101
	clearDisplay();
102
103
	document.getElementById("midright").scroll(0, 0);
104
105
	const ts = isInt? ae.GetIntMsgTime(num) : ae.GetExtMsgTime(num);
106
107
	document.getElementById("btn_reply").disabled = false;
108
	document.getElementById("btn_reply").onclick = function() {
109
		document.getElementById("write_recv").value = isInt? ae.GetIntMsgFrom(num) : ae.GetExtMsgFrom(num);
110
		document.getElementById("write_subj").value = "Re: " + (isInt ? ae.GetIntMsgTitle(num) : ae.GetExtMsgTitle(num));
111
		document.getElementById("write_rply").textContent = (isInt? "" : getMsgId(num));
112
		document.getElementById("btn_write").click();
113
		document.getElementById("div_write_1").hidden = false;
114
		document.getElementById("div_write_2").hidden = true;
115
		document.getElementById("write_body").focus();
116
		for (const opt of document.getElementById("write_from").options) {
117
			if (opt.value === (isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num))) {
118
				opt.selected = true;
119
			}
120
		}
121
	};
122
123
	document.getElementById("btn_mdele").disabled = false;
124
	document.getElementById("btn_mdele").onclick = function() {
125
		this.blur();
126
127
		ae.Message_Delete(isInt? ae.GetIntMsgIdHex(num) : ae.GetExtMsgIdHex(num), function(success) {
128
			if (!success) console.log("Failed delete");
129
		});
130
	};
131
132
	document.getElementById("midright").children[0].hidden = false;
133
	document.getElementById("midright").children[1].textContent = isInt ? ae.GetIntMsgTitle(num) : ae.GetExtMsgTitle(num);
134
	document.getElementById("midright").children[2].textContent = isInt ? ae.GetIntMsgBody(num) : ae.GetExtMsgBody(num);
135
136
	document.getElementById("readmsg_to").textContent = isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num);
137
	document.getElementById("readmsg_date").children[0].textContent = new Date(ts * 1000).toISOString().slice(0, 19).replace("T", " ");
138
139
	if (!isInt) {
140
		document.getElementById("readmsg_ip").hidden = false;
141
		document.getElementById("readmsg_country").hidden = false;
142
		document.getElementById("readmsg_tls").hidden = false;
143
		document.getElementById("readmsg_greet").hidden = false;
144
		document.getElementById("readmsg_timing").hidden = false;
145
		document.getElementById("readmsg_envfrom").hidden = false;
146
147
		const cc = ae.GetExtMsgCountry(num);
148
149
		document.getElementById("readmsg_ip").children[0].textContent = ae.GetExtMsgIp(num);
150
		document.getElementById("readmsg_country").textContent = getCountryFlag(cc) + " " + getCountryName(cc);
151
		document.getElementById("readmsg_tls").children[0].textContent = ae.GetExtMsgTLS(num);
152
		document.getElementById("readmsg_greet").children[0].textContent = ae.GetExtMsgGreet(num);
153
		document.getElementById("readmsg_envfrom").textContent = ae.GetExtMsgFrom(num);
154
155
		let flagText = "";
156
		if (!ae.GetExtMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
157
		if (!ae.GetExtMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
158
		if (!ae.GetExtMsgFlagPExt(num)) flagText += "<abbr title=\"The sender did not use the Extended (ESMTP) protocol\">SMTP</abbr> ";
159
		if (!ae.GetExtMsgFlagQuit(num)) flagText += "<abbr title=\"The sender did not issue the required QUIT command\">QUIT</abbr> ";
160
		if (ae.GetExtMsgFlagRare(num)) flagText += "<abbr title=\"The sender issued unusual command(s)\">RARE</abbr> ";
161
		if (ae.GetExtMsgFlagFail(num)) flagText += "<abbr title=\"The sender issued invalid command(s)\">FAIL</abbr> ";
162
		if (ae.GetExtMsgFlagPErr(num)) flagText += "<abbr title=\"The sender violated the protocol\">PROT</abbr> ";
163
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
164
	} else {
165
		document.getElementById("readmsg_ip").hidden = true;
166
		document.getElementById("readmsg_country").hidden = true;
167
		document.getElementById("readmsg_tls").hidden = true;
168
		document.getElementById("readmsg_greet").hidden = true;
169
		document.getElementById("readmsg_timing").hidden = true;
170
		document.getElementById("readmsg_envfrom").hidden = true;
171
172
		let symbol = "<span title=\"Invalid level\">&#x26a0;</span>";
173
		if (ae.GetIntMsgFrom(num) === "system") {if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"System\">&#x1f162;</span>";} // S (System)
174
		else if (ae.GetIntMsgLevel(num) === 0) symbol = "<span title=\"Level 0 User\">&#x1f10c;</span>"; // 0
175
		else if (ae.GetIntMsgLevel(num) === 1) symbol = "<span title=\"Level 1 User\">&#x278a;</span>"; // 1
176
		else if (ae.GetIntMsgLevel(num) === 2) symbol = "<span title=\"Level 2 User\">&#x278b;</span>"; // 2
177
		else if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"Administrator\">&#x1f150;</span>"; // A (Admin)
178
		document.getElementById("readmsg_from").innerHTML = symbol + " " + ae.GetIntMsgFrom(num);
179
180
		let flagText = "";
181
		if (!ae.GetIntMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
182
		if (!ae.GetIntMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
183
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
184
	}
185
}
186
187
// Interface
188
function addMsg(isInt, i) {
189
	const row = document.getElementById("tbl_inbox").insertRow(-1);
190
	const cellTime = row.insertCell(-1);
191
	const cellSubj = row.insertCell(-1);
192
	const cellSnd1 = row.insertCell(-1);
193
	const cellSnd2 = row.insertCell(-1);
194
195
	const ts = isInt? ae.GetIntMsgTime(i) : ae.GetExtMsgTime(i);
196
	cellTime.setAttribute("data-ts", ts);
197
	cellTime.textContent = new Date(ts * 1000).toISOString().slice(0, 10);
198
199
	cellSubj.textContent = isInt? ae.GetIntMsgTitle(i) : ae.GetExtMsgTitle(i);
200
201
	if (isInt) {
202
		cellSnd1.textContent = ae.GetIntMsgFrom(i);
203
		cellSnd1.className = (ae.GetIntMsgFrom(i).length === 16) ? "mono" : "";
204
	} else {
205
		const from1 = ae.GetExtMsgFrom(i);
206
		const from2 = from1.substring(from1.indexOf("@") + 1);
207
		const cc = ae.GetExtMsgCountry(i);
208
209
		cellSnd1.textContent = from1.substring(0, from1.indexOf("@"));
210
211
		const flag = document.createElement("abbr");
212
		flag.textContent = getCountryFlag(cc);
213
		flag.title = getCountryName(cc);
214
		cellSnd2.appendChild(flag);
215
216
		const fromText = document.createElement("span");
217
		fromText.textContent = " " + from2;
218
		cellSnd2.appendChild(fromText);
219
	}
220
221
	row.onclick = function() {
222
		displayMsg(isInt, i);
223
	};
224
}
225
226
function getRowsPerPage() {
227
	const tbl = document.getElementById("tbl_inbox");
228
	tbl.innerHTML = "";
229
	const row = tbl.insertRow(-1);
230
	const cell = row.insertCell(-1);
231
	cell.textContent = "0";
232
233
	const rowsPerPage = Math.floor(getComputedStyle(document.getElementById("div_inbox")).height.replace("px", "") / getComputedStyle(document.querySelector("#tbl_inbox > tbody > tr:first-child")).height.replace("px", "")) - 1; // -1 allows space for 'load more'
234
	tbl.innerHTML = "";
235
	return rowsPerPage;
236
}
237
238
function addMessages() {
239
	const rowsPerPage = getRowsPerPage();
240
	let skipMsgs = rowsPerPage * tabs[TAB_INBOX].cur;
241
242
	const maxExt = ae.GetExtMsgCount();
243
	const maxInt = ae.GetIntMsgCount();
244
245
	tabs[TAB_INBOX].max = Math.floor((maxExt + maxInt) / rowsPerPage);
246
247
	let numExt = 0;
248
	let numInt = 0;
249
	let numAdd = 0;
250
251
	while (numAdd < rowsPerPage) {
252
		const tsInt = (numInt < maxInt) ? ae.GetIntMsgTime(numInt) : -1;
253
		const tsExt = (numExt < maxExt) ? ae.GetExtMsgTime(numExt) : -1;
254
		if (tsInt === -1 && tsExt === -1) break;
255
256
		if (tsInt !== -1 && (tsExt === -1 || tsInt > tsExt)) {
257
			if (skipMsgs > 0) skipMsgs--; else {addMsg(true, numInt); numAdd++;}
258
			numInt++;
259
		} else if (tsExt !== -1) {
260
			if (skipMsgs > 0) skipMsgs--; else {addMsg(false, numExt); numAdd++;}
261
			numExt++;
262
		}
263
	}
264
265
	if (ae.GetReadyMsgKilos() < ae.GetTotalMsgKilos()) {
266
		const inbox = document.getElementById("tbl_inbox");
267
		const row = inbox.insertRow(-1);
268
		const cell = row.insertCell(-1);
269
		cell.textContent = "Load more (" + (ae.GetTotalMsgKilos() - ae.GetReadyMsgKilos()) + " KiB left)";
270
271
		row.onclick = function() {
272
			this.onclick = "";
273
274
			ae.Message_Browse(false, function(successBrowse) {
275
				document.getElementById("tbl_inbox").style.opacity = 1;
276
277
				if (successBrowse) {
278
					addMessages();
279
					if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
280
				}
281
			});
282
		};
283
	}
284
}
285
286
function addUploads() {
287
	const tbl = document.getElementById("tbd_uploads");
288
	tbl.innerHTML = "";
289
290
	for (let i = 0; i < ae.GetUplMsgCount(); i++) {
291
		const row = tbl.insertRow(-1);
292
		let cell;
293
		cell = row.insertCell(-1); cell.textContent = new Date(ae.GetUplMsgTime(i) * 1000).toISOString().slice(0, 10);
294
295
		cell = row.insertCell(-1); cell.textContent = ae.GetUplMsgTitle(i);
296
		cell.onclick = function() {displayFile(this.parentElement.rowIndex - 1);};
297
298
		cell = row.insertCell(-1); cell.textContent = ""; // Format
299
		cell = row.insertCell(-1); cell.textContent = ""; // Size
300
301
		cell = row.insertCell(-1); cell.innerHTML = "<button data-msgid=\"" + ae.GetUplMsgIdHex(i) + "\" type=\"button\">X</button>";
302
		cell.children[0].onclick = function() {
303
			const tr = this.parentElement.parentElement;
304
			ae.Message_Delete(this.getAttribute("data-msgid"), function(success) {
305
				if (success) tr.remove();
306
			});
307
		};
308
	}
309
}
310
311
function updateAddressCounts() {
312
	document.getElementById("limit_normal").textContent = (ae.GetAddressCountNormal() + "/" + ae.GetAddressLimitNormal(ae.GetUserLevel())).padStart(ae.GetAddressLimitNormal(ae.GetUserLevel()) > 9 ? 5 : 1);
313
	document.getElementById("limit_shield").textContent = (ae.GetAddressCountShield() + "/" + ae.GetAddressLimitShield(ae.GetUserLevel())).padStart(ae.GetAddressLimitShield(ae.GetUserLevel()) > 9 ? 5 : 1);
314
	document.getElementById("limit_total").textContent = ((ae.GetAddressCountNormal() + ae.GetAddressCountShield()) + "/" + ae.GetAddrPerUser()).padStart(5);
315
}
316
317
function adjustLevel(pubkey, level, c) {
318
	const fs = document.getElementById("fs_accs");
319
	fs.disabled = true;
320
321
	ae.Account_Update(pubkey, level, function(success) {
322
		fs.disabled = false;
323
324
		if (success) {
325
			c[4].textContent = level;
326
			c[5].children[0].disabled = (level === 3);
327
			c[6].children[0].disabled = (level === 0);
328
		}
329
	});
330
}
331
332
function addAccountToTable(i) {
333
	const tblAccs = document.getElementById("tbd_accs");
334
	const row = tblAccs.insertRow(-1);
335
	let cell;
336
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserPkHex(i);
337
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSpace(i);
338
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserNAddr(i);
339
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSAddr(i);
340
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserLevel(i);
341
342
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">+</button>";
343
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent) + 1, c);};
344
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 3);
345
346
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">&minus;</button>";
347
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent) - 1, c);};
348
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 0);
349
350
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">X</button>";
351
	cell.children[0].onclick = function() {
352
		const tr = this.parentElement.parentElement;
353
		ae.Account_Delete(tr.cells[0].textContent, function(success) {
354
			if (success) tr.remove();
355
		});
356
	};
357
}
358
359
function reloadAccount() {
360
	// Limits
361
	const tblLimits = document.getElementById("tbl_limits");
362
	for (let i = 0; i < 4; i++) {
363
		tblLimits.rows[i].cells[1].children[0].value = ae.GetStorageLimit(i) + 1;
364
		tblLimits.rows[i].cells[2].children[0].value = ae.GetAddressLimitNormal(i);
365
		tblLimits.rows[i].cells[3].children[0].value = ae.GetAddressLimitShield(i);
366
	}
367
368
	// Accounts
369
	const tblAccs = document.getElementById("tbd_accs");
370
371
	// All: Our account
372
	const row = tblAccs.insertRow(-1);
373
	let cell;
374
	cell = row.insertCell(-1); cell.textContent = ae.GetUserPkHex();
375
	cell = row.insertCell(-1); cell.textContent = Math.round(ae.GetTotalMsgKilos() / 1024);
376
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountNormal();
377
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountShield();
378
	cell = row.insertCell(-1); cell.textContent = ae.GetUserLevel();
379
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\" disabled=\"disabled\">+</button>";
380
381
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_downme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">&minus;</button>";
382
	cell.children[0].onclick = function() {
383
		const newLevel = parseInt(row.cells[4].textContent) - 1;
384
		ae.Account_Update(ae.GetUserPkHex(), newLevel, function(success) {
385
			if (success) row.cells[4].textContent = newLevel;
386
		});
387
	};
388
389
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_killme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">X</button>";
390
	cell.children[0].onclick = function() {
391
		ae.Account_Delete(ae.GetUserPkHex(), function(success) {
392
			if (success) row.remove();
393
		});
394
	};
395
396
	// Admin: Other accounts
397
	if (ae.IsUserAdmin()) {
398
		for (let i = 0; i < ae.Admin_GetUserCount(); i++) {
399
			addAccountToTable(i);
400
		}
401
	}
402
403
	document.getElementById("txt_reg").disabled = !ae.IsUserAdmin();
404
	document.getElementById("btn_reg").disabled = !ae.IsUserAdmin();
405
406
	// Contacts
407
	for (let i = 0; i < ae.GetContactCount(); i++) {
408
		addContact(
409
			ae.GetContactMail(i),
410
			ae.GetContactName(i),
411
			ae.GetContactNote(i)
412
		);
413
	}
414
415
	// Addresses
416
	for (let i = 0; i < ae.GetAddressCount(); i++) {
417
		addAddress(i);
418
	}
419
420
	updateAddressCounts();
421
}
422
423 View Code Duplication
function deleteAddress(addr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
424
	let btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
425
	for (let i = 0; i < btns.length; i++) btns[i].disabled = true;
426
427
	let addressToDelete = -1;
428
429
	for (let i = 0; i < ae.GetAddressCount(); i++) {
430
		if (addr === ae.GetAddress(i)) {
431
			addressToDelete = i;
432
			break;
433
		}
434
	}
435
436
	if (addressToDelete === -1) return;
437
438
	ae.Address_Delete(addressToDelete, function(success) {
439
		if (success) {
440
			document.getElementById("tbl_addrs").deleteRow(addressToDelete);
441
			document.getElementById("write_from").remove(addressToDelete);
442
			updateAddressCounts();
443
444
			if (ae.GetAddressCountNormal() < ae.GetAddressLimitNormal(ae.GetUserLevel())) document.getElementById("btn_address_create_normal").disabled = false;
445
			if (ae.GetAddressCountShield() < ae.GetAddressLimitShield(ae.GetUserLevel())) document.getElementById("btn_address_create_shield").disabled = false;
446
447
			ae.Private_Update(function(success2) {
448
				if (!success2) console.log("Failed to update the Private field");
449
450
				btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
451
				for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
452
			});
453
		} else {
454
			console.log("Failed to delete address");
455
456
			btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
457
			for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
458
		}
459
	});
460
}
461
462 View Code Duplication
function shieldMix(addr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
463
	let newAddr = "";
464
465
	for (let i = 0; i < 16; i++) {
466
		switch (addr.charAt(i)) {
467
			case '1':
468
				newAddr += "1iIlL".charAt(Math.floor(Math.random() * 5));
469
				break;
470
			case '0':
471
				newAddr += "0oO".charAt(Math.floor(Math.random() * 3));
472
				break;
473
			case 'w':
474
				newAddr += "VvWw".charAt(Math.floor(Math.random() * 4));
475
				break;
476
			default:
477
				newAddr += (Math.random() > 0.5) ? addr.charAt(i) : addr.charAt(i).toUpperCase();
478
		}
479
	}
480
481
	return newAddr;
482
}
483
484
function addAddress(num) {
485
	const addrTable = document.getElementById("tbl_addrs");
486
	const row = addrTable.insertRow(-1);
487
	const cellAddr = row.insertCell(-1);
488
	const cellChk1 = row.insertCell(-1);
489
	const cellChk2 = row.insertCell(-1);
490
	const cellChk3 = row.insertCell(-1);
491
	const cellBtnD = row.insertCell(-1);
492
493
	cellAddr.textContent = ae.GetAddress(num);
494
	cellAddr.onclick = function() {
495
		if (cellAddr.textContent.length === 16)
496
			navigator.clipboard.writeText(shieldMix(cellAddr.textContent) + "@" + ae.GetDomainEml());
1 ignored issue
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
497
		else
498
			navigator.clipboard.writeText(cellAddr.textContent + "@" + ae.GetDomainEml());
499
	};
500
501
	cellChk1.innerHTML = ae.GetAddressAccExt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
502
	cellChk2.innerHTML = ae.GetAddressAccInt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
503
	cellChk3.innerHTML = ae.GetAddressUse_Gk(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
504
505
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
506
	cellBtnD.onclick = function() {deleteAddress(cellAddr.textContent);};
507
508
	const opt = document.createElement("option");
509
	opt.value = cellAddr.textContent;
510
	opt.textContent = cellAddr.textContent + "@" + ae.GetDomainEml();
511
	document.getElementById("write_from").appendChild(opt);
512
}
513
514
document.getElementById("btn_dele").onclick = function() {
515
	this.blur();
516
517
	if (tab === TAB_WRITE) {
518
		tabs[tab].cur = 0;
519
		updateTab();
520
521
		document.getElementById("write_recv").value = "";
522
		document.getElementById("write_subj").value = "";
523
		document.getElementById("write_body").value = "";
524
525
		document.getElementById("write_recv").focus();
526
	}
527
};
528
529
document.getElementById("btn_updt").onclick = function() {
530
	const btn = this;
531
	btn.disabled = true;
532
	btn.blur();
533
534
	if (tab === TAB_INBOX) {
535
		document.getElementById("tbl_inbox").style.opacity = 0.5;
536
537
		ae.Message_Browse(true, function(successBrowse) {
538
			document.getElementById("tbl_inbox").style.opacity = 1;
539
540
			if (successBrowse) {
541
				addMessages();
542
				addUploads();
543
				btn.disabled = false;
544
			} else {
545
				console.log("Failed to refresh");
546
				btn.disabled = false;
547
			}
548
		});
549
	}
550
};
551
552
function addContact(mail, name, note) {
553
	const tbl = document.getElementById("tbl_ctact");
554
	const row = tbl.insertRow(-1);
555
	const cellMail = row.insertCell(-1);
556
	const cellName = row.insertCell(-1);
557
	const cellNote = row.insertCell(-1);
558
	const cellBtnD = row.insertCell(-1);
559
560
	cellMail.textContent = mail;
561
	cellName.textContent = name;
562
	cellNote.textContent = note;
563
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
564
565
	cellMail.contentEditable = true;
566
	cellName.contentEditable = true;
567
	cellNote.contentEditable = true;
568
569
	cellBtnD.onclick = function() {row.remove();};
570
}
571
572
document.getElementById("btn_newcontact").onclick = function() {
573
	addContact("", "", "");
574
};
575
576
document.getElementById("btn_savecontacts").onclick = function() {
577
	while (ae.GetContactCount() > 0) {
578
		ae.DeleteContact(0);
579
	}
580
581
	for (const row of document.getElementById("tbl_ctact").rows) {
582
		ae.AddContact(row.cells[0].textContent, row.cells[1].textContent, row.cells[2].textContent);
583
	}
584
585
	const btn = this;
586
	btn.disabled = true;
587
588
	ae.Private_Update(function(success) {
589
		btn.disabled = false;
590
591
		if (!success) {
592
			console.log("Failed contacts update");
593
		}
594
	});
595
};
596
597
function updateTab() {
598
	switch (tab) {
599
		case TAB_INBOX:
600
			addMessages();
601
		break;
602
603
		case TAB_WRITE:
604
			switch (tabs[tab].cur) {
605
				case 0: // Write
606
					document.getElementById("div_write_1").hidden = false;
607
					document.getElementById("div_write_2").hidden = true;
608
					document.getElementById("write_body").focus();
609
				break;
610
611
				case 1: // Verify
612
					ae.Address_Lookup(document.getElementById("write_recv").value, function(pk) {
613
						if (pk) {
614
							document.getElementById("div_write_1").hidden = true;
615
							document.getElementById("div_write_2").hidden = false;
616
617
							document.getElementById("write2_from").textContent = document.getElementById("write_from").value + "@" + ae.GetDomainEml();
618
							document.getElementById("write2_recv").textContent = document.getElementById("write_recv").value;
619
							document.getElementById("write2_pkey").textContent = sodium.to_hex(pk);
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
620
621
							document.getElementById("write2_subj").textContent = document.getElementById("write_subj").value;
622
							document.getElementById("write2_rply").textContent = document.getElementById("write_rply").textContent;
623
							document.getElementById("write2_body").textContent = document.getElementById("write_body").value;
624
						} else {
625
							console.log("Failed lookup");
626
						}
627
					});
628
				break;
629
630
				case 2: // Send
631
					ae.Message_Create(
632
						document.getElementById("write_subj").value,
633
						document.getElementById("write_body").value,
634
						document.getElementById("write_from").value,
635
						document.getElementById("write_recv").value,
636
						document.getElementById("write_rply").textContent,
637
						(document.getElementById("write2_recv").textContent.indexOf("@") > 0) ? null : sodium.from_hex(document.getElementById("write2_pkey").textContent),
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
638
						function(success) {
639
							if (success) {
640
								console.log("Sent ok");
641
							} else {
642
								console.log("Failed sending");
643
							}
644
						}
645
					);
646
				break;
647
			}
648
		break;
649
650
		case TAB_NOTES:
651
			for (let i = 0; i <= tabs[tab].max; i++) {
652
				document.getElementById("div_notes").children[i].hidden = (i !== tabs[tab].cur);
653
			}
654
		break;
655
656
		case TAB_TOOLS:
657
			for (let i = 0; i <= tabs[tab].max; i++) {
658
				document.getElementById("div_tools").children[i].hidden = (i !== tabs[tab].cur);
659
			}
660
		break;
661
	}
662
663
	document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
664
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
665
}
666
667
document.getElementById("btn_left").onclick = function() {
668
	tabs[tab].cur--;
669
	if (tabs[tab].cur === 0) this.disabled = true;
670
	if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
671
	updateTab();
672
	this.blur();
673
};
674
675
document.getElementById("btn_rght").onclick = function() {
676
	tabs[tab].cur++;
677
	if (tabs[tab].cur === tabs[tab].max) this.disabled = true;
678
	document.getElementById("btn_left").disabled = false;
679
	updateTab();
680
	this.blur();
681
};
682
683
const buttons = document.querySelector("#main1 > .top").getElementsByTagName("button");
684
for (let i = 0; i < buttons.length; i++) {
685
	buttons[i].onclick = function() {
686
		tab = i;
687
688
		for (let j = 0; j < buttons.length; j++) {
689
			document.querySelector("#main1 > .mid").children[j].hidden = (tab !== j);
690
			buttons[j].disabled = (tab === j);
691
		}
692
693
		document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
0 ignored issues
show
Bug introduced by
The variable tab is changed as part of the for loop for example by i on line 686. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
694
		document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
695
		document.getElementById("btn_dele").disabled = !tabs[tab].btnDele;
696
		document.getElementById("btn_updt").disabled = !tabs[tab].btnUpdt;
697
	};
698
}
699
700
function addressCreate(addr) {
701
	const btnN = document.getElementById("btn_address_create_normal");
702
	const btnS = document.getElementById("btn_address_create_shield");
703
	btnN.disabled = true;
704
	btnS.disabled = true;
705
706
	ae.Address_Create(addr, function(success1) {
707
		if (success1) {
708
			ae.Private_Update(function(success2) {
709
				addAddress(ae.GetAddressCount() - 1);
710
				if (addr !== "SHIELD") document.getElementById("txt_address_create_normal").value = "";
711
				updateAddressCounts();
712
713
				if (!success2) console.log("Failed to update the Private field");
714
715
				if (ae.GetAddressCountNormal() < ae.GetAddressLimitNormal(ae.GetUserLevel())) btnN.disabled = false;
716
				if (ae.GetAddressCountShield() < ae.GetAddressLimitShield(ae.GetUserLevel())) btnS.disabled = false;
717
			});
718
		} else {
719
			console.log("Failed to add address");
720
721
			if (ae.GetAddressCountNormal() < ae.GetAddressLimitNormal(ae.GetUserLevel())) btnN.disabled = false;
722
			if (ae.GetAddressCountShield() < ae.GetAddressLimitShield(ae.GetUserLevel())) btnS.disabled = false;
723
		}
724
	});
725
}
726
727
document.getElementById("btn_address_create_normal").onclick = function() {
728
	if (ae.GetAddressCountNormal() >= ae.GetAddressLimitNormal(ae.GetUserLevel())) return;
729
730
	const txtNewAddr = document.getElementById("txt_address_create_normal");
731
	if (!txtNewAddr.reportValidity()) return;
732
733
	addressCreate(txtNewAddr.value);
734
};
735
736
document.getElementById("btn_address_create_shield").onclick = function() {
737
	if (ae.GetAddressCountShield() >= ae.GetAddressLimitShield(ae.GetUserLevel())) return;
738
739
	addressCreate("SHIELD");
740
};
741
742
document.getElementById("btn_reg").onclick = function() {
743
	const btn = document.getElementById("btn_reg");
744
	const txt = document.getElementById("txt_reg");
745
	if (!txt.reportValidity()) return;
746
	btn.disabled = true;
747
748
	ae.Account_Create(txt.value, function(success) {
749
		if (success) {
750
			addAccountToTable(ae.Admin_GetUserCount() - 1);
751
			txt.value = "";
752
		}
753
754
		btn.disabled = false;
755
	});
756
};
757
758
document.getElementById("chk_downme").onclick = function() {document.getElementById("btn_downme").disabled = !this.checked;};
759
document.getElementById("chk_killme").onclick = function() {document.getElementById("btn_killme").disabled = !this.checked;};
760
761
document.getElementById("btn_notepad_saveupl").onclick = function() {
762
	const np = document.getElementById("txt_notepad");
763
	np.disabled = true;
764
765
	let fname = prompt("Save as...", "Untitled");
0 ignored issues
show
Debugging Code Best Practice introduced by
The prompt UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
766
	if (!fname.endsWith(".txt")) fname += ".txt";
767
768
	ae.Message_Upload(fname, np.value, function(success) {
769
		if (success) {
770
			np.value = "";
771
			addUploads();
772
		}
773
774
		console.log("Failed to add text");
775
		np.disabled = false;
776
	});
777
};
778
779
document.getElementById("btn_upload").onclick = function() {
780
	const fileSelector = document.createElement("input");
781
	fileSelector.type = "file";
782
	fileSelector.click();
783
784
	const f = fileSelector.files[0];
0 ignored issues
show
Unused Code introduced by
The constant f seems to be never used. Consider removing it.
Loading history...
785
786
	const btn = this;
787
	btn.disabled = true;
788
789
	const reader = new FileReader();
1 ignored issue
show
Bug introduced by
The variable FileReader seems to be never declared. If this is a global, consider adding a /** global: FileReader */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
790
	reader.onload = function() {
791
		ae.Message_Upload(fileSelector.files[0].name, new Uint8Array(reader.result), function(success) {
792
			if (success) {
793
				addUploads();
794
			} else {
795
				console.log("Failed upload");
796
			}
797
798
			btn.disabled = false;
799
		});
800
	};
801
802
	reader.readAsArrayBuffer(fileSelector.files[0]);
803
};
804
805
document.getElementById("txt_skey").onkeyup = function(event) {
806
	if (event.key === "Enter") {
807
		event.preventDefault();
808
		document.getElementById("btn_enter").click();
809
	}
810
};
811
812
document.getElementById("btn_enter").onclick = function() {
813
	const txtSkey = document.getElementById("txt_skey");
814
	if (!txtSkey.reportValidity()) return;
815
816
	const btn = this;
817
	btn.disabled = true;
818
	document.getElementById("txt_skey").style.background = "#233";
819
820
	ae.SetKeys(txtSkey.value, function(successSetKeys) {
821
		if (successSetKeys) {
822
			ae.Account_Browse(0, function(successBrowse) {
823
				if (successBrowse) {
824
					txtSkey.value = "";
825
826
					reloadAccount();
827
					document.getElementById("div_begin").hidden = true;
828
					document.getElementById("div_main").style.display = "grid";
829
830
					document.getElementById("btn_updt").click();
831
				} else {
832
					console.log("Failed to enter");
833
					btn.disabled = false;
834
					document.getElementById("txt_skey").style.background = "#466";
835
					txtSkey.focus();
836
				}
837
			});
838
		} else {
839
			console.log("Invalid format for key");
840
			btn.disabled = false;
841
			document.getElementById("txt_skey").style.background = "#466";
842
			txtSkey.focus();
843
		}
844
	});
845
};
846
847
});
848